<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务，帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);

namespace app\common\service\qrcode;

use app\common\model\store\shop\Clerk as clerkUserModel;
use Exception;
use Grafika\Color;
use Grafika\Grafika;

/**
 * 二维码
 * Class Qrcode
 * @package app\common\service
 */
class Card extends BaseQRcode
{
    // 分销商用户信息
    /* @var clerkUserModel $clerk */
    private $clerk;

    // 分销商海报设置
    private $channel;

    /**
     * 构造方法
     * Poster constructor.
     * @param clerkUserModel $clerk
     * @param string $channel 二维码渠道(小程序码、h5码)
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function __construct(clerkUserModel $clerk, string $channel = 'MP-WEIXIN')
    {

        parent::__construct();
        // 分销商用户信息
        $this->clerk = $clerk;
        // 二维码渠道
        $this->channel = $channel;

    }

    /**
     * 获取分销二维码
     * @return string
     * @throws \app\common\exception\BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws Exception
     */
    public function getImage(): string
    {
        // 如果已生成过，则直接返回url
        if (file_exists($this->getPosterPath())) {
            //return $this->getPosterUrl();
        }
        // 商城ID
        $storeId = (int) $this->clerk['store_id'];

        // 海报背景图
        $backdrop = __DIR__ . '/resource/card-bg.png';
        //$backdrop = web_path() . 'temp/bg.png';
        // 2. 下载用户头像
        $avatarUrl = $this->userAvatar();
        $avatar    = $this->saveTempImage($storeId, $avatarUrl, 'avatar');


            // 2. 下载背景图
        $cardImage = $this->clerk['shop']['card_image_url'];
        $cardImage    = $this->saveTempImage($storeId, $cardImage, 'avatar');


        // 3. 下载二维码
        $scene  = 'uid:' . $this->clerk['clerk_id'] . ',sid:' . $this->clerk['shop_id'].',source:2';
        $qrcode = $this->getQrcode($storeId, $scene, 'pagesNew/shop/share', $this->channel);
        // 4. 拼接海报图
        return $this->savePoster($backdrop, $avatar,$cardImage, $qrcode);
    }

    /**
     * 获取用户头像
     * @return string
     */
    private function userAvatar(): string
    {
        $avatar = $this->clerk['user']['avatar'];
        //$default = __DIR__ . '/resource/default-avatar.png';
        $default = base_url() . 'temp/default-avatar.png';
        return ! empty($avatar) ? $avatar['external_url'] : $default;
    }

    /**
     * 海报图文件路径
     * @return string
     */
    private function getPosterPath(): string
    {
        // 保存路径
        $tempPath = web_path() . "temp/{$this->clerk['store_id']}/";
        ! is_dir($tempPath) && mkdir($tempPath, 0755, true);
        return $tempPath . $this->getPosterName();
    }

    /**
     * 海报图文件名称
     * @return string
     */
    private function getPosterName(): string
    {
        return "poster_{$this->channel}_{$this->clerk['user_id']}" . '.png';
    }

    /**
     * 海报图url
     * @return string
     */
    private function getPosterUrl(): string
    {
        return base_url() . "temp/{$this->clerk['store_id']}/" . $this->getPosterName() . '?t=' . time();
    }

    /**
     * 拼接海报图
     * @param string $backdrop 背景图路径
     * @param string $avatar 头像路径
     * @param string $qrcode 二维码路径
     * @return string
     * @throws Exception
     */
    private function savePoster(string $backdrop, string $avatar,string $card_image, string $qrcode): string
    {

        // 实例化图像编辑器
        $editor = Grafika::createEditor(['Gd']);

        $fontPath    = Grafika::fontsDir() . '/st-heiti-light.ttc';
        // 打开海报背景图
        $editor->open($backdropImage, $backdrop);
   

        // 打开
       $editor->open($cardImage,$card_image);
        //重设用户头像宽高
        $avatarWidth = 750;
        $avatarHeight = 450;
        $editor->resizeExact($cardImage, $avatarWidth, $avatarHeight);
        // 用户头像添加到背景图
        $avatarX = 0;
        $avatarY = 0;
        $editor->blend($backdropImage, $cardImage, 'normal', 1.0, 'top-left', $avatarX, $avatarY);


        // 生成圆形用户头像
        $this->circular($avatar, $avatar);
        // 打开用户头像
        $editor->open($avatarImage, $avatar);
        // 重设用户头像宽高
        $avatarWidth = 120;
        $editor->resizeExact($avatarImage, $avatarWidth, $avatarWidth);
        // 用户头像添加到背景图
        $avatarX = 315;
        $avatarY = 390;
        $editor->blend($backdropImage, $avatarImage, 'normal', 1.0, 'top-left', $avatarX, $avatarY);

        // 生成圆形二维码
        // $this->config['qrcode']['style'] === 'circle' && $this->circular($qrcode, $qrcode);
        // 打开二维码

        $this->circular($qrcode, $qrcode);
        $editor->open($qrcodeImage, $qrcode);
        // 重设二维码宽高
        $qrcodeWidth = 150;
        $editor->resizeExact($qrcodeImage, $qrcodeWidth, $qrcodeWidth);
        // 二维码添加到背景图
        $qrcodeX = 540;
        $qrcodeY = 1058;

        $editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', $qrcodeX, $qrcodeY);

        // 写入用户昵称
        
        $fontSize    = 18;
        $outsideName = $this->wrapText((int)$fontSize, 0, $fontPath, $this->clerk['real_name'], 150, 1);

        $str_width = $this->wrapTextWidth((int)$fontSize, 0, $fontPath, $this->clerk['real_name'], 150, 1);
        if ($str_width >= 750) {
            $mLeft = 0;
        } else {
            $mLeft = 750 - $str_width;
            $mLeft = $mLeft / 2;
        }



        $editor->text($backdropImage, $outsideName, $fontSize, $mLeft, 520, new Color('#000000'), $fontPath);

     
        // 写入店铺名称
        // $fontSize = 14 * 2 * 0.76;
        // $fontX = 100 * 2;
        // $fontY = 80 * 2;
        // $Color = new Color('#FFF');
        // $fontPath = Grafika::fontsDir() . '/st-heiti-light.ttc';
        // $editor->text($backdropImage, $this->clerk['shop']['shop_name'], $fontSize, $fontX, $fontY, $Color, $fontPath);

        // 写入店铺地址
        $fontSize = 24 * 0.76;
        $fontX    = 90;
        $fontY    = 1115;
        $Color    = new Color('#111');
        $fontPath = Grafika::fontsDir() . '/st-heiti-light.ttc';
        $editor->text($backdropImage, $this->clerk['shop']['address'], $fontSize, $fontX, $fontY, $Color, $fontPath);

         // 写入联系电话
        $fontSize = 24 * 0.76;
         $fontX    = 90;
        $fontY    = 1068;
        $Color    = new Color('#111');
        $fontPath = Grafika::fontsDir() . '/st-heiti-light.ttc';
        $editor->text($backdropImage, $this->clerk['shop']['phone'], $fontSize, $fontX, $fontY, $Color, $fontPath);

        // 保存图片
        $editor->save($backdropImage, $this->getPosterPath());
        return $this->getPosterUrl();
    }
    private function wrapTextWidth(int $fontsize, int $angle, string $fontface, string $string, int $width, int $maxLine = null): float
    {
        // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
        $content = "";
        // 将字符串拆分成一个个单字 保存到数组 letter 中
        $letter = [];
        for ($i = 0; $i < mb_strlen($string, 'UTF-8'); $i++) {
            $letter[] = mb_substr($string, $i, 1, 'UTF-8');
        }
        $line_count = 0;
        foreach ($letter as $l) {
            $testbox = imagettfbbox($fontsize, $angle, $fontface, $content . ' ' . $l);
            // 判断拼接后的字符串是否超过预设的宽度
            if (($testbox[2] > $width) && ($content !== "")) {
                $line_count++;
                if ($maxLine && $line_count >= $maxLine) {
                    $content = mb_substr($content, 0, -1, 'UTF-8') . "...";
                    break;
                }
                $content .= "\n";
            }
            $content .= $l;
        }
        return $testbox[2];
    }
    /**
     * 处理文字超出长度自动换行
     * @param integer $fontsize 字体大小
     * @param integer $angle 角度
     * @param string $fontface 字体名称
     * @param string $string 字符串
     * @param integer $width 预设宽度
     * @param int|null $maxLine 最多行数
     * @return string
     */
    private function wrapText(int $fontsize, int $angle, string $fontface, string $string, int $width, int $maxLine = null): string
    {
        // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
        $content = "";
        // 将字符串拆分成一个个单字 保存到数组 letter 中
        $letter = [];
        for ($i = 0; $i < mb_strlen($string, 'UTF-8'); $i++) {
            $letter[] = mb_substr($string, $i, 1, 'UTF-8');
        }
        $line_count = 0;
        foreach ($letter as $l) {
            $testbox = imagettfbbox($fontsize, $angle, $fontface, $content . ' ' . $l);
            // 判断拼接后的字符串是否超过预设的宽度
            if (($testbox[2] > $width) && ($content !== "")) {
                $line_count++;
                if ($maxLine && $line_count >= $maxLine) {
                    $content = mb_substr($content, 0, -1, 'UTF-8') . "...";
                    break;
                }
                $content .= "\n";
            }
            $content .= $l;
        }
        return $content;
    }
    /**
     * 生成圆形图片
     * @param string $imgpath 图片地址
     * @param string $saveName 保存文件名，默认空。
     */
    private function circular(string $imgpath, string $saveName = '')
    {
        $srcImg = imagecreatefromstring(file_get_contents($imgpath));
        $w      = imagesx($srcImg);
        $h      = imagesy($srcImg);
        $w      = $h      = min($w, $h);
        $newImg = imagecreatetruecolor($w, $h);
        // 这一句一定要有
        imagesavealpha($newImg, true);
        // 拾取一个完全透明的颜色,最后一个参数127为全透明
        $bg = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
        imagefill($newImg, 0, 0, $bg);
        $r = $w / 2; //圆半径
        for ($x = 0; $x < $w; $x++) {
            for ($y = 0; $y < $h; $y++) {
                $rgbColor = imagecolorat($srcImg, $x, $y);
                if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) {
                    imagesetpixel($newImg, $x, $y, $rgbColor);
                }
            }
        }
        // 输出图片到文件
        imagepng($newImg, $saveName);
        // 释放空间
        imagedestroy($srcImg);
        imagedestroy($newImg);
    }
}
